import json
from urllib.parse import urlencode, parse_qs
from urllib.request import urlopen
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadData
from django.conf import settings

# import json
import logging

from . import constants
from .exceptions import QQAPIException

logger = logging.getLogger('django')


class OAuthQQ(object):
    """
    QQ登录的工具类
    过程
    """

    def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):
        """构造方法 接受所有工具方法需要使用的参数"""
        self.client_id = client_id or settings.QQ_CLIENT_ID
        self.client_secret = client_secret or settings.QQ_CLIENT_SECRET
        # QQ_REDIRECT_URI = 'http://www.meiduo.site:8080/oauth_callback.html'
        self.redirect_uri = redirect_uri or settings.QQ_REDIRECT_URI
        self.state = state or settings.QQ_STATE  # 用于保存登录成功后的跳转页面路径

    def get_qq_login_url(self):
        """
        提供QQ扫码登陆链接的url
        :return: url网址
        """
        # 准备参数
        # 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=xx&redirext_url=xx&'
        # 必须自己补充url
        login_url = 'https://graph.qq.com/oauth2.0/authorize?'
        params = {
            # 固定不变
            'response_type': 'code',  # 标识扫码后未来得到code(获取access_token的凭据)
            # APPid
            # 外界传入
            # 'client_id': "101474184",
            'client_id': self.client_id,  # 创建应用的标识
            # 'redirect_uri': "http://www.meiduo.site:8080/oauth_callback.html",
            'redirect_uri': self.redirect_uri,  # 扫码成功后跳转的路径界面
            # 'state': "next",
            'state': self.state,  # QQ登录成功后回去的地方
            # 默认
            'scope': 'get_user_info',  # 标识扫码最终为了获取QQ用户的信息
        }
        # 拼接QQ扫码登陆
        login_url += urlencode(params)

        return login_url

    def get_access_token(self, code):
        """
        获取access_token
        :param code: qq提供的code
        :return: access_token
        """

        # 准备url
        url = 'https://graph.qq.com/oauth2.0/token?'

        # 准备参数
        params = {
            'grant_type': 'authorization_code',
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': code,
            'redirect_uri': self.redirect_uri
        }

        # 拼接地址
        url += urlencode(params)

        try:
            # 使用code向QQ服务器发送请求 获取access_token
            response = urlopen(url)
            print("response:", response)

            # 获取响应的二进制
            response_data = response.read()
            print("response_data:", response_data)

            # 将二进制转化为字符串
            response_str = response_data.decode()
            print("response_str:", response_str)

            # response_data转化为字典 str转化为字典
            response_dict = parse_qs(response_str)
            print("response_dict", response_dict)

            # 提取access_token
            access_token = response_dict.get('access_token')[0]
        except Exception as e:
            logger.error(e)
            raise QQAPIException("获取access_token失败")

        # if not access_token:
        #     logger.error('code=%s msg=%s' % (data.get('code'), data.get('msg')))
        #     raise QQAPIError

        return access_token

    def get_openid(self, access_token):
        """
        获取用户的openid
        :param access_token: qq提供的access_token
        :return: open_id
        """
        url = 'https://graph.qq.com/oauth2.0/me?access_token=' + access_token
        response_str = ""
        try:
            response = urlopen(url)
            response_str = response.read().decode()
            print("response_str:", response_str)
            # 返回的数据 callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )\n;
            response_dict = json.loads(response_str[10:-4])
            openid = response_dict.get("openid")
        except Exception as e:
            data = parse_qs(response_str)
            logger.error(e)
            raise QQAPIException("code=%s msg=%s" % (data.get("code"), data.get("msg")))
        return openid

    @staticmethod
    def generate_save_user_token(openid):
        """
        生成保存用户数据的token
        :param openid: 用户的openid
        :return: token
        """
        serializer = Serializer(settings.SECRET_KEY, expires_in=constants.SAVE_QQ_USER_TOKEN_EXPIRES)
        data = {"openid": openid}
        token = serializer.dumps(data)
        return token.decode()

    @staticmethod
    def check_save_user_token(token):
        """
        检验保存用户数据的token
        :param token: token
        :return: openid or None
        """
        serializer = Serializer(settings.SECRET_KEY, expires_in=constants.SAVE_QQ_USER_TOKEN_EXPIRES)
        try:
            print("token:",token)
            data = serializer.loads(token)
        except BadData:
            return None
        else:
            return data.get('openid')
